package com.oriole.admin.utils;

import com.oriole.common.util.ArithUtil;
import com.oriole.common.util.DateUtils;
import com.oriole.common.util.IpUtil;
import com.oriole.entity.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

/**
 * Created by IntelliJ IDEA.
 *
 * @author doublelife
 * Date: 2020/8/31 22:50
 * description: 系统环境监控工具类
 */
public class SystemMonitorUtil {

    private static final Logger log = LoggerFactory.getLogger(SystemMonitorUtil.class);

    private static final int OSHI_WAIT_SECOND = 1000;

    private static SystemInfo SYSTEM_INFO = new SystemInfo();
    private static MonitorVo MONITOR_VO = new MonitorVo();

    static {
        System.out.println(1);
    }

    public static MonitorVo getSysMonitor() {
        HardwareAbstractionLayer hardware = SYSTEM_INFO.getHardware();
        // cpu信息
        MONITOR_VO.setCpuVo(getCpuVo(hardware.getProcessor()));
        // 设置内存信息
        MONITOR_VO.setMemoryVo(getMemoryVo(hardware.getMemory()));
        // 设置服务器信息
        MONITOR_VO.setSystemVo(getSystemVo());
        // JVM相关信息
        MONITOR_VO.setJvmVo(getJvmVo());
        // 设置磁盘信息
        MONITOR_VO.setHardDiskVos(getHardDiskVos(SYSTEM_INFO.getOperatingSystem()));
        return MONITOR_VO;
    }

    /**
     * 设置CPU信息
     */
    private static CpuVo getCpuVo(CentralProcessor processor) {
        // CPU信息
        CpuVo cpuVo = new CpuVo();
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        cpuVo.setCpuNum(processor.getLogicalProcessorCount());
        cpuVo.setTotal(ArithUtil.round(ArithUtil.mul(totalCpu, 100), 2));
        cpuVo.setSys(ArithUtil.round(ArithUtil.mul((double)cSys / totalCpu, 100), 2));
        cpuVo.setUsed(ArithUtil.round(ArithUtil.mul((double)user / totalCpu, 100), 2));
        cpuVo.setWait(ArithUtil.round(ArithUtil.mul((double)iowait / totalCpu, 100), 2));
        cpuVo.setFree(ArithUtil.round(ArithUtil.mul((double)idle / totalCpu, 100), 2));
        return cpuVo;
    }

    /**
     * 设置内存信息
     */
    private static MemoryVo getMemoryVo(GlobalMemory memory) {
        MemoryVo memoryVo = new MemoryVo();
        long total = memory.getTotal();
        long available = memory.getAvailable();
        long used = total - available;
        memoryVo.setTotal(ArithUtil.div(total, (1024 * 1024 * 1024), 2));
        memoryVo.setUsed(ArithUtil.div(used, (1024 * 1024 * 1024), 2));
        memoryVo.setFree(ArithUtil.div(available, (1024 * 1024 * 1024), 2));
        memoryVo.setUseRate(ArithUtil.mul(ArithUtil.div(used, total, 4), 100));
        return memoryVo;
    }

    /**
     * 设置服务器信息
     */
    private static SystemVo getSystemVo() {
        SystemVo systemVo = new SystemVo();
        Properties props = System.getProperties();
        systemVo.setComputerName(IpUtil.getHostName());
        systemVo.setComputerIp(IpUtil.getHostIp());
        systemVo.setUserDir(props.getProperty("user.dir"));
        systemVo.setOsName(props.getProperty("os.name"));
        systemVo.setOsArch(props.getProperty("os.arch"));
        return systemVo;
    }

    /**
     * 设置Java虚拟机
     */
    private static JvmVo getJvmVo() {
        JvmVo jvmVo = new JvmVo();
        Properties props = System.getProperties();
        long total = Runtime.getRuntime().totalMemory();
        long max = Runtime.getRuntime().maxMemory();
        long free = Runtime.getRuntime().freeMemory();
        long used = total - free;
        long startTime = ManagementFactory.getRuntimeMXBean().getStartTime();

        jvmVo.setTotal(ArithUtil.div(total, (1024 * 1024), 2));
        jvmVo.setMax(ArithUtil.div(max, (1024 * 1024), 2));
        jvmVo.setFree(ArithUtil.div(free, (1024 * 1024), 2));
        jvmVo.setUsed(ArithUtil.div(used, (1024 * 1024), 2));
        jvmVo.setUseRate(ArithUtil.mul(ArithUtil.div(used, total, 4), 100));
        jvmVo.setJdkVersion(props.getProperty("java.version"));
        jvmVo.setJdkHome(props.getProperty("java.home"));
        jvmVo.setJdkName(ManagementFactory.getRuntimeMXBean().getVmName());
        jvmVo.setJdkStartTime(DateUtils.defaultDateToStr(new Date(startTime)));
        jvmVo.setJdkRunTime(DateUtils.getDatePoor(new Date(), new Date(startTime)));
        return jvmVo;
    }

    /**
     * 设置磁盘信息
     */
    private static List<HardDiskVo> getHardDiskVos(OperatingSystem os) {
        List<HardDiskVo> hardDiskVos = new LinkedList<>();
        FileSystem fileSystem = os.getFileSystem();
        List<OSFileStore> fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            HardDiskVo hardDiskVo = new HardDiskVo();
            hardDiskVo.setDirName(fs.getMount());
            hardDiskVo.setSysTypeName(fs.getType());
            hardDiskVo.setTypeName(fs.getName());
            hardDiskVo.setTotal(convertFileSize(total));
            hardDiskVo.setFree(convertFileSize(free));
            hardDiskVo.setUsed(convertFileSize(used));
            hardDiskVo.setUsage(ArithUtil.mul(ArithUtil.div(used, total, 4), 100));
            hardDiskVos.add(hardDiskVo);
        }
        return hardDiskVos;
    }

    /**
     * 字节转换
     *
     * @param size 字节大小
     * @return 转换后值
     */
    public static String convertFileSize(long size) {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) {
            return String.format("%.1f GB", (float) size / gb);
        } else if (size >= mb) {
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        } else if (size >= kb) {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        } else {
            return String.format("%d B", size);
        }
    }

}
